package main

import (
	".go-fox-edge-channel-opc-ua/Initialize"
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"github.com/gopcua/opcua"
	"github.com/gopcua/opcua/ua"
	"log"
	"math/big"
	"net/url"
	"time"
)

func main() {
	Initialize.Initialize()
}

func generateCert() (*tls.Certificate, error) {
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, fmt.Errorf("生成私钥失败: %v", err)
	}

	notBefore := time.Now()
	notAfter := notBefore.Add(365 * 24 * time.Hour) // 有效期1年
	serialNumber, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization: []string{"My Client"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		ExtKeyUsage: []x509.ExtKeyUsage{
			x509.ExtKeyUsageClientAuth,
			x509.ExtKeyUsageServerAuth,
		},
		BasicConstraintsValid: true,
	}

	// 设置证书的URI标识（需与服务器信任的客户端标识匹配）
	host := "urn:my:client"
	if uri, err := url.Parse(host); err == nil {
		template.URIs = append(template.URIs, uri)
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return nil, fmt.Errorf("创建证书失败: %v", err)
	}

	// 编码为PEM格式
	certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	keyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(priv),
	})

	cert, err := tls.X509KeyPair(certPEM, keyPEM)
	return &cert, err
}

func main2() {
	// 生成证书
	cert, err := generateCert()
	if err != nil {
		log.Fatal("生成证书失败:", err)
	}
	pk, ok := cert.PrivateKey.(*rsa.PrivateKey)
	if !ok {
		log.Fatal("私钥类型错误")
	}

	// 获取服务器端点并选择安全策略
	ctx := context.Background()
	endpoints, err := opcua.GetEndpoints(ctx, "opc.tcp://LAPTOP-9JI6D0AU:53530/OPCUA/SimulationServer")
	if err != nil {
		log.Fatal("获取端点失败:", err)
	}

	// 选择支持的安全策略（例如Basic256Sha256）
	policy := ua.SecurityPolicyURIBasic256Sha256
	mode := ua.MessageSecurityModeSignAndEncrypt
	ep, err := opcua.SelectEndpoint(endpoints, policy, mode)

	// 配置客户端选项
	opts := []opcua.Option{
		opcua.SecurityPolicy(policy),
		opcua.SecurityMode(mode),
		opcua.Certificate(cert.Certificate[0]),
		opcua.PrivateKey(pk),
		opcua.AuthUsername("username", "password"), // 可选用户名密码认证
		opcua.SecurityFromEndpoint(ep, ua.UserTokenTypeCertificate),
		opcua.AutoReconnect(true),
	}

	client, err := opcua.NewClient("opc.tcp://LAPTOP-9JI6D0AU:53530/OPCUA/SimulationServer", opts...)
	if err := client.Connect(ctx); err != nil {
		log.Fatal("连接失败:", err)
	}
	defer client.Close(ctx)

	// 读取节点示例
	nodeID := ua.NewNumericNodeID(0, 2258)
	resp, err := client.Node(nodeID).Value(ctx)
	if err != nil {
		log.Fatal("读取节点失败:", err)
	}
	fmt.Println("节点值:", resp.Value)
}
